package com.freak.kotlinfitnessserver.factory

import android.bluetooth.BluetoothGattCharacteristic

open class GattParses {
    companion object {
        /**
         * Characteristic value format type uint24
         */
        const val FORMAT_UINT24: Int = 0x1
    }

    /**
     * Returns the size of a give value type.
     */
    private fun getTypeLen(formatType: Int): Int {
        return formatType and 0xF
    }


    /**
     * Convert a signed byte to an unsigned int.
     */
    private fun unsignedByteToInt(b: Byte): Int {
        return b.toInt() and 0xFF
    }

    /**
     * Convert signed bytes to a 16-bit unsigned int.
     */
    private fun unsignedBytesToInt(b0: Byte, b1: Byte): Int {
        return unsignedByteToInt(b0) +
                (unsignedByteToInt(b1) shl 8)
    }

    /**
     * Convert signed bytes to a 32-bit unsigned int.
     * shl 左移操作
     */
    private fun unsignedBytesToInt(b0: Byte, b1: Byte, b2: Byte, b3: Byte): Int {
        return (unsignedByteToInt(b0) +
                (unsignedByteToInt(b1) shl 8) +
                (unsignedByteToInt(b2) shl 16) +
                (unsignedByteToInt(b3) shl 24))
    }

    /**
     * Convert signed bytes to a 24-bit unsigned int.
     * shl 左移操作
     */
    private fun unsignedBytesToInt(b0: Byte, b1: Byte, b2: Byte): Int {
        return (unsignedByteToInt(b0) +
                (unsignedByteToInt(b1) shl 8) +
                (unsignedByteToInt(b2) shl 16))
    }

    /**
     * Convert signed bytes to a 16-bit short float value.
     */
    private fun bytesToFloat(b0: Byte, b1: Byte): Float {
        val mantissa = unsignedToSigned(
            unsignedByteToInt(b0) +
                    (unsignedByteToInt(b1) and 0x0F shl 8), 12
        )
        // shr 右移操作
        val exponent = unsignedToSigned(unsignedByteToInt(b1) shr 4, 4)
        return (mantissa * Math.pow(10.0, exponent.toDouble())).toFloat()
    }

    /**
     * Convert signed bytes to a 32-bit short float value.
     */
    private fun bytesToFloat(b0: Byte, b1: Byte, b2: Byte, b3: Byte): Float {
        val mantissa = unsignedToSigned(
            (unsignedByteToInt(b0) +
                    (unsignedByteToInt(b1) shl 8) +
                    (unsignedByteToInt(b2) shl 16)),
            24
        )
        return (mantissa * Math.pow(10.0, b3.toDouble())).toFloat()
    }

    /**
     * Convert an unsigned integer value to a two's-complement encoded
     * signed value.
     */
    private fun unsignedToSigned(unsigned: Int, size: Int): Int {
        var unsigned = unsigned
        if ((unsigned and (1 shl (size - 1))) != 0) {
            unsigned = -1 * ((1 shl (size - 1)) - (unsigned and ((1 shl (size - 1)) - 1)))
        }
        return unsigned
    }

    /**
     * Convert an integer into the signed bits of a given length.
     */
    private fun intToSignedBits(i: Int, size: Int): Int {
        var i = i
        if (i < 0) {
            i = (1 shl (size - 1)) + (i and ((1 shl (size - 1)) - 1))
        }
        return i
    }

    fun getIntValue(value: ByteArray, formatType: Int, offset: Int): Int {
        if (offset + getTypeLen(formatType) > value.size) {
            return -1
        }
        when (formatType) {
            BluetoothGattCharacteristic.FORMAT_UINT8 -> return unsignedByteToInt(value[offset])

            BluetoothGattCharacteristic.FORMAT_UINT16 -> return unsignedBytesToInt(
                value[offset], value[offset + 1]
            )

            BluetoothGattCharacteristic.FORMAT_UINT32 -> return unsignedBytesToInt(
                value[offset], value[offset + 1], value[offset + 2], value[offset + 3]
            )

            FORMAT_UINT24 -> return unsignedBytesToInt(
                value[offset], value[offset + 1], value[offset + 2]
            )

            BluetoothGattCharacteristic.FORMAT_SINT8 -> return unsignedToSigned(
                unsignedByteToInt(
                    value[offset]
                ), 8
            )

            BluetoothGattCharacteristic.FORMAT_SINT16 -> return unsignedToSigned(
                unsignedBytesToInt(
                    value[offset], value[offset + 1]
                ), 16
            )

            BluetoothGattCharacteristic.FORMAT_SINT32 -> return unsignedToSigned(
                unsignedBytesToInt(
                    value[offset], value[offset + 1], value[offset + 2], value[offset + 3]
                ), 32
            )
        }
        return -1
    }

    fun getFloatValue(value: ByteArray, formatType: Int, offset: Int): Float {
        if (offset + getTypeLen(formatType) > value.size) return -1f
        when (formatType) {
            BluetoothGattCharacteristic.FORMAT_SFLOAT -> return bytesToFloat(
                value[offset], value[offset + 1]
            )

            BluetoothGattCharacteristic.FORMAT_FLOAT -> return bytesToFloat(
                value[offset], value[offset + 1], value[offset + 2], value[offset + 3]
            )
        }
        return -1f
    }

    fun getStringValue(value: ByteArray, offset: Int): String? {
        if (offset > value.size) return null
        val strBytes = ByteArray(value.size - offset)
        for (i in 0 until value.size - offset) {
            strBytes[i] = value[offset + i]
        }
        return String(strBytes)
    }
}